package com;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class ProxyUtil {

    public static Object newInstance(Object target){
        Object proxy = null;
        // 拼接字符串java文件
        Class targetInf = target.getClass().getInterfaces()[0];
        // 获取所有的方法
        Method[] declaredMethods = targetInf.getDeclaredMethods();
        // \r\n
        String line = System.lineSeparator();
        String tab = "\t";
        // 获取类的名称 System.class System
        String infName = targetInf.getSimpleName();
        String context = "";
        // package com;
        String packageContext = "package com.hxy.proxy;" + line;
        // import com.MyService;
        String importContext = "import "+ targetInf.getName() + ";" +line;
        String clazzFirstLineContext = "public class $Proxy implements " +infName + "{" +line;
        String filedContent = tab + "private " + infName + " target;" + line;
        String constructorContent = tab + "public $Proxy (" + infName + " target){" + line
                + tab + tab + "this.target =target;"
                + line + tab + "}" + line;
        String methodContent = "";
        for (Method method : declaredMethods) {
            String returnTypeName = method.getReturnType().getSimpleName();
            String methodName = method.getName();
            // Sting.class String.class
            Class args[] = method.getParameterTypes();
            String argsContent = "";
            String paramsContent = "";
            int flag = 0;
            for (Class arg : args) {
                String temp = arg.getSimpleName();
                //String
                //String p0,Sting p1,
                argsContent += temp + " p" + flag + ",";
                paramsContent += "p" + flag + ",";
                flag++;
            }
            if (argsContent.length() > 0) {
                argsContent = argsContent.substring(0, argsContent.lastIndexOf(",") - 1);
                paramsContent = paramsContent.substring(0, paramsContent.lastIndexOf(",") - 1);
            }

            methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {" + line
                    + tab + tab + "System.out.println(\"proxy print log for " + methodName + "\");" + line
                    + tab + tab + "target." + methodName + "(" + paramsContent + ");" + line
                    + tab + "}" + line;

        }
        // 以上是拼接java文件
        context = packageContext + importContext + clazzFirstLineContext + filedContent + constructorContent + methodContent + "}";
        // 生成java文件
        File file = new File("E:\\com\\hxy\\proxy\\$Proxy.java");
        try {
            if(!file.exists()){
                file.createNewFile();
             }
            FileWriter fw = new FileWriter(file);
            fw.write(context);
            fw.flush();
            fw.close();

            // 开始编译java
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
            JavaCompiler.CompilationTask task = compiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
            task.call();
            standardFileManager.close();
            // 加载class
            URL[] urls = new URL[]{new URL("file:E:\\\\")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class<?> clazz = urlClassLoader.loadClass("com.hxy.proxy.$Proxy");
            System.out.println(targetInf);
            // 通过构造方法去创建对象
            Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
            Constructor<?> declaredConstructor = declaredConstructors[0];
            proxy = declaredConstructor.newInstance(target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return proxy;
    }

    public static void main(String[] args) {
        MyServiceImpl target = new MyServiceImpl();
        MyService o = (MyService) ProxyUtil.newInstance(target);
        o.test01();
        o.test02("test02");
    }
}
